package dao

import javax.inject.Inject
import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider}
import slick.jdbc.JdbcProfile

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import models.Tables._


/**
 * Created by yz on 2018/12/27
 */
class MissionDao @Inject()(protected val dbConfigProvider: DatabaseConfigProvider) extends
  HasDatabaseConfigProvider[JdbcProfile] {

  import profile.api._

  import com.github.tototoshi.slick.MySQLJodaSupport._

  type MyRow = MissionRow
  val table = Mission

  def insert(row: MissionRow): Future[Unit] = db.run(Mission += row).map(_ => ())

  def insertAndReturnId(row: MissionRow) = {
    val action = {
      val insert = table returning table.map(_.id) += row
      insert
    }.transactionally
    db.run(action)
  }

  def insertOrUpdates(ts: List[(MissionRow, ExtraDataRow, TrashRow)]) = {
    val action = {
      val fs = ts.map { case (missionRow, extraRow, trashRow) =>
        if (missionRow.id == 0) {
          val missionInsert = table returning table.map(_.id) += missionRow
          missionInsert.flatMap { id =>
            val newExtraRow = extraRow.copy(id = id)
            val extraInsert = ExtraData += newExtraRow
            val newTrashRow = trashRow.copy(id = id)
            val trashInsert = Trash += newTrashRow
            extraInsert.zip(trashInsert).map { x =>
              id
            }
          }
        } else {
          val missionUpdate = table.filter(_.id === missionRow.id).update(missionRow)
          val extraUpdate = ExtraData.filter(_.id === extraRow.id).update(extraRow)
          missionUpdate.zip(extraUpdate).map { x =>
            missionRow.id
          }
        }
      }
      DBIO.sequence(fs)
    }.transactionally
    db.run(action)
  }

  def update(row: MissionRow) = {
    val action = {
      table.filter(_.id === row.id).update(row)
    }.transactionally
    db.run(action)
  }

  def insertAndRetunIds(rows: Seq[MissionRow]) = {
    val action = {
      Mission returning Mission.map(_.id) ++= rows
    }.transactionally
    db.run(action)
  }

  def selectAll: Future[Seq[MissionRow]] = db.run(Mission.result)

  def selectByMissionId(missionId: Int): Future[MissionRow] = db.run(Mission.filter(_.id === missionId).result.head)

  def selectAll(sampleId: String, userId: Int) = db.run(table.join(Trash).on(_.id === _.id).
    filter { x =>
      x._1.sampleId === sampleId && x._1.userId === userId
    }.map(_._1).sortBy(_.endTime.desc).result)

  def selectAll(userId: Int) = db.run(table.join(Trash).on(_.id === _.id).
    filter { x =>
      x._1.userId === userId && x._2.exist
    }.map(_._1).result)

  def selectOp(row: MissionRow) = db.run(table.join(Trash).on(_.id === _.id).
    filter { x =>
      x._1.sampleId === row.sampleId && x._1.userId === row.userId && x._1.endTime === row.endTime && x._2.exist
    }.map(_._1).result.headOption)

  def selectByMissionIds(missionIds: Seq[Int]): Future[Seq[MissionRow]] = db.run(Mission.
    filter(_.id.inSetBind(missionIds)).sortBy(_.endTime.desc).result)

  def deleteById(id: Int): Future[Unit] = db.run(Mission.filter(_.id === id).delete).map(_ => ())

  def deleteByUserId(userId: Int): Future[Unit] = db.run(Mission.filter(_.userId === userId).delete).map(_ => ())

  def deleteAll = db.run(Mission.delete).map(_ => ())

  def deleteByIds(ids: Seq[Int]): Future[Unit] = db.run(Mission.filter(_.id.inSetBind(ids)).delete).map(_ => ())


}
